package org.cxn.tools.thread;


import org.cxn.tools.config.PropertiesTool;

import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Created by chenxiangning on 15-5-6.
 */
public class ThreadPoolManager {
    /**
     * corePoolSize - 池中所保存的线程数，包括空闲线程。
     * maximumPoolSize-池中允许的最大线程数。
     * keepAliveTime - 当线程数大于核心时，此为终止前多余的空闲线程等待新任务的最长时间。
     * unit - keepAliveTime 参数的时间单位。
     * workQueue - 执行前用于保持任务的队列。此队列仅保持由 execute方法提交的 Runnable任务。
     * threadFactory - 执行程序创建新线程时使用的工厂。
     * handler - 由于超出线程范围和队列容量而使执行被阻塞时所使用的处理程序。
     * ThreadPoolExecutor是Executors类的底层实现。
     */
    private static int corePoolSize;
    private static int maximumPoolSize;
    private static int keepAliveTime;
    private static int workQueueSize;

    static {
        corePoolSize = PropertiesTool.singlton()
                .getPropertyToInt("corePoolSize");
        maximumPoolSize = PropertiesTool.singlton()
                .getPropertyToInt("maximumPoolSize");
        keepAliveTime = PropertiesTool.singlton()
                .getPropertyToInt("keepAliveTime");
        workQueueSize = PropertiesTool.singlton()
                .getPropertyToInt("workQueueSize");
    }

    private int unit;

    private ThreadPoolExecutor fixedThreadPool;
    private ThreadPoolExecutor singleThreadExecutor;
    private ThreadPoolExecutor cachedThreadPool;
    private ThreadPoolExecutor arrayBlockingQueuePool;

    private ThreadPoolManager(){}

    private static class SingltonHolder{
        private static ThreadPoolManager instance = new ThreadPoolManager();
    }

    public final static ThreadPoolManager instance(){
        return SingltonHolder.instance;
    }


    // 任务缓冲队列
    private Queue<Runnable> taskQueue = new LinkedList<Runnable>();
    /*
	 * 线程池超出界线时将任务加入缓冲队列
	 */
    final RejectedExecutionHandler taskHandler = new RejectedExecutionHandler() {
        public void rejectedExecution(Runnable task, ThreadPoolExecutor executor) {
            taskQueue.offer(task);
        }
    };

    final class MyThreadFactory implements ThreadFactory {
        final ThreadGroup group;
        final String namePrefix;
        final AtomicInteger poolNumber = new AtomicInteger(1);

        public MyThreadFactory() {
            SecurityManager s = System.getSecurityManager();
            group = (s != null) ? s.getThreadGroup() :
                    Thread.currentThread().getThreadGroup();
            namePrefix = "请求处理线程池-" +
                    poolNumber.getAndIncrement() +
                    "-org.cxn.tools.thread-";
        }

        final AtomicInteger threadNumber = new AtomicInteger(1);

        public Thread newThread(Runnable r) {

            Thread t = new Thread(Thread.currentThread().getThreadGroup(), r, "topPatternTasklet-org.cxn.tools.thread"
                    + (threadNumber.getAndIncrement()));

            t.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {

                public void uncaughtException(Thread t, Throwable e) {
                    System.out.println(t.getName()+" ####  "+e);
                }

            });
            return t;
        }
    }

    /**
     * queue上的三种类型。
     * 排队有三种通用策略
     * 直接提交。工作队列的默认选项是 SynchronousQueue，它将任务直接提交给线程而不保持它们。
     * 在此，如果不存在可用于立即运行任务的线程，则试图把任务加入队列将失败，因此会构造一个新的线程。
     * 所以在使用SynchronousQueue通常要求maximumPoolSize是无界的
     * 此策略可以避免在处理可能具有内部依赖性的请求集时出现锁。直接提交通常要求无界 maximumPoolSizes
     * 以避免拒绝新提交的任务。当命令以超过队列所能处理的平均数连续到达时，此策略允许无界线程具有增长的可能性。
     *
     * 无界队列。使用无界队列（例如，不具有预定义容量的 LinkedBlockingQueue）
     * 将导致在所有 corePoolSize 线程都忙时新任务在队列中等待。这样，创建的线程就不会超过 corePoolSize。
     * （因此，maximumPoolSize的值也就无效了。）当每个任务完全独立于其他任务，即任务执行互不影响时，
     * 适合于使用无界队列；例如，在 Web页服务器中。这种排队可用于处理瞬态突发请求，当命令以超过队列所能处理的平均数连续到达时，
     * 此策略允许无界线程具有增长的可能性。
     *
     * 有界队列。当使用有限的 maximumPoolSizes时，有界队列（如 ArrayBlockingQueue）有助于防止资源耗尽，
     * 但是可能较难调整和控制。
     * 队列大小和最大池大小可能需要相互折衷：使用大型队列和小型池可以最大限度地降低 CPU 使用率、
     * 操作系统资源和上下文切换开销，但是可能导致人工降低吞吐量。
     * 如果任务频繁阻塞（例如，如果它们是 I/O边界），则系统可能为超过您许可的更多线程安排时间。
     * 使用小型队列通常要求较大的池大小，CPU使用率较高，但是可能遇到不可接受的调度开销，这样也会降低吞吐量。
     */


    /**
     * 构建固定大小的线程池
     */
    public ThreadPoolExecutor buildFixedThreadPool(int threadNum){
        if (fixedThreadPool != null) {
            return fixedThreadPool;
        }
        // 最后的BlockingQueue选择了LinkedBlockingQueue，该queue有一个特点，他是无界的
        fixedThreadPool = new ThreadPoolExecutor(threadNum,threadNum,
                0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>());

        return fixedThreadPool;
    }

    /**
     * 构建单线程的线程池
     * ExecutorService  newSingleThreadExecutor()：单线程
     * @return
     */
    public ThreadPoolExecutor buildSingleThreadExecutor(){
        if (singleThreadExecutor != null) {
            return singleThreadExecutor;
        }
        singleThreadExecutor = new ThreadPoolExecutor(1,1,
                0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>());
        return singleThreadExecutor;
    }

    /**
     * 构建无界限的线程池.
     * ExecutorService newCachedThreadPool()：无界线程池，可以进行自动线程回收
     * 首先是无界的线程池，所以我们可以发现maximumPoolSize为big
     * 其次BlockingQueue的选择上使用SynchronousQueue
     * 该SynchronousQueue中，每个插入操作必须等待另一个线程的对应移除操作
     * @return
     */
    public ThreadPoolExecutor buildCachedThreadPool(){
        if (cachedThreadPool != null) {
            return cachedThreadPool;
        }
        cachedThreadPool = new ThreadPoolExecutor(0,Integer.MAX_VALUE,
                60L,TimeUnit.SECONDS,
                new SynchronousQueue<Runnable>());

        return cachedThreadPool;
    }
    /**
     * 构建有界限的线程池.
     * @return
     */
    public ThreadPoolExecutor buildArrayBlockingQueuePool(){
        if (arrayBlockingQueuePool != null) {
            return arrayBlockingQueuePool;
        }
        arrayBlockingQueuePool = new ThreadPoolExecutor(corePoolSize,maximumPoolSize,
                60L,TimeUnit.SECONDS,
                new ArrayBlockingQueue<Runnable>(workQueueSize),
                new MyThreadFactory(),taskHandler);

        return arrayBlockingQueuePool;
    }


}
